home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / H-K / Help Package ƒ / Help Package.p < prev   
Encoding:
Text File  |  1992-06-10  |  26.4 KB  |  626 lines  |  [TEXT/PJMM]

  1. unit HelpPackage;
  2.  
  3. {******************************************************    *}
  4. {*    This is a package of routines to be used for setting your own menu items in the      *}
  5. {*    Help menu under System 7 or building a new menu with the title stored in the        *}
  6. {* Global constant HELPMENUTITLE.  The menu is appended to the end of the menu bar    *}
  7. {*  active during the call to Init Help. The source code was written by Tim Damon in    *}
  8. {* THINK Pascal.  It is encouraged to be used in any developement projects, but           *}
  9. {*    PLEASE at least give me credit for the long hours of frustrating work.  If you            *}
  10. {*    wish to use this in a commercial product, please contact me via America Online     *}
  11. {*    or mail (Addresses are listed in the documention file.)  so I can keep track of who *}
  12. {*    is using it and for which products.  Feel free to distribute the  source code to        *}
  13. {* anyone and everyone.  All I ask is that if you decide to modify the code, please       *}
  14. {*    let me know so I can borrow your ideas! : )  If you find a better way of doing           *}
  15. {*    things I would appreciate hearing about it.  Any other questions or comments?           *}
  16. {*    Contact me.   All rights reserved. ©1992 Mountainside Software.  Tim Damon       *}
  17. {******************************************************    *}
  18.  
  19. interface
  20.  
  21.     uses
  22.         HelpGlobals, Traps, Types, GestaltEqu, Balloons;
  23. {*HelpGlobals is the unit containing all global variabls for this package.*}
  24. {*They must be global to your application as well for the sake of keeping data integrity.*}
  25.  
  26.     const
  27.         TextBox = 2;                {*The item number of the text box user item in the Help dialog*}
  28.             {*Must be global to this unit for update events*}
  29.     var
  30.         TEXTHandle: TEHandle;        {*The text edit handle for the text*}
  31.             {*Must be global to this unit for update events*}
  32.         TheScrollBar: ControlHandle;        {*The handle to the scroll bar*}
  33.             {*Must be global to this unit for tracking the scrollbar in the Help dialog*}
  34.  
  35.     function InitHelp (HmiLID: integer): Integer;
  36. {*Make a call to this function, providing the resource ID of your main 'HmiL', when setting up your menus.*}
  37. {*This function sets up the Help menu using the 'HmiL' resources you provide. * }
  38. {*It will return an error code if it has a problem setting up the menu.*}
  39.  
  40.     function DoHelp (MenuID, TheItem: integer): Integer;
  41. {*Make a call to this function when your event loop detects a menu choice.  Give it the menu ID*}
  42. {*and the Item number returned from MenuSelect.  The function will return with NoMenu*}
  43. {*if the menu was not associated with the Help menu from System 7 or the Help menu built*}
  44. {*under an earlier system.  If the routine returns with a value other than zero, chances are*}
  45. {*the help dialog never showed up.*}
  46.  
  47.     procedure DisposeHelp;
  48. {*Make a call to this routine to dispose of the current Help menu items and data structeres*}
  49. {*This can be called at anytime during execution.*}
  50.  
  51. implementation
  52. {------------------------------------------------------------------------------}
  53. {-The following routines were taken from Inside Macintosh Volume VI, Chapter 3, pg 8-}
  54. {------------------------------------------------------------------------------}
  55.     function NumToolboxTraps: Integer;
  56.     begin
  57.         if NGetTrapAddress(_InitGraf, ToolTrap) = NGetTrapAddress($AA6E, ToolTrap) then
  58.             NumToolboxTraps := $200
  59.         else
  60.             NumToolboxTraps := $400;
  61.     end;
  62.  
  63.     function GetTrapType (theTrap: Integer): TrapType;
  64.         const
  65.             TrapMask = $0800;
  66.     begin
  67.         if BAND(theTrap, TrapMask) > 0 then
  68.             GetTrapType := ToolTrap
  69.         else
  70.             GetTrapType := OSTrap;
  71.     end;
  72.  
  73.     function TrapAvailable (theTrap: Integer): Boolean;
  74.         var
  75.             tType: TrapType;
  76.     begin
  77.         tType := GetTrapType(theTrap);
  78.         if tType = ToolTrap then
  79.             begin
  80.                 theTrap := BAND(theTrap, $07FF);
  81.                 if theTrap >= NumToolboxTraps then
  82.                     theTrap := _Unimplemented;
  83.             end;
  84.         TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress(_Unimplemented, ToolTrap);
  85.     end;
  86. {-----------------------------------------------------------------------}
  87.  
  88.  
  89.     function BuildMenu (HmiLID: Integer; TheMenuHandle: MenuHandle; whichMenu: Integer; var Err: Integer): MHandle;
  90. {*InitHelp calls this function, providing the resource ID of your main 'HmiL', to actually build the Help Menu.*}
  91. {*This function sets up the Help menu using the 'HmiL' resources you provide. * }
  92. {*It will return an error code if it has a problem setting up the menu. InitHelp will return this error code to you.*}
  93.         type
  94.             ItemListForm = record            {*This record contains an item from them 'HmiL' resource.*}
  95.                     HierMenu: Boolean;
  96.                     HierMenuID: Integer;
  97.                     HierMItemListID: Integer;
  98.                     HelpTextID: Integer;
  99.                 end;
  100.             IListPtr = ^ItemListForm;                {*This is a pointer to the ItemListForm record.*}
  101.             intPtr = ^integer;                        {*Needed to extract an integer off the top of the 'HmiL' resource.*}
  102.  
  103.         var
  104.             TempMHandle: MHandle;
  105.         {*A temporary handle used to make sure the handle was allocated properly.*}
  106.         {*Also for working with fields of the record.*}
  107.             TempMasterHandle: MHandle;    {*Used to build the master handle of the menu list.*}
  108.             TheMasterHandle: MHandle;    {*This points to the first item of the master item list.*}
  109.             RHandle: Handle;                {*A handle to the 'HmiL' resource.*}
  110.             Count: Integer;                    {*This contains the number of items in the 'HmiL' resource.*}
  111.             Address: Longint;                {*This will be used in indexing into the 'HmiL' resource.*}
  112.             TempItemRec: IListPtr;        {*A pointer to an item record.*}
  113.             TheItemTitle: Str255;            {*Hold the items title when working with the 'HmiL' resource.*}
  114.             HierMHandle: MenuHandle;        {*A handle to a new hierarchical menu.*}
  115.             TempPtr: StringPtr;            {*A temporary pointer to the title.*}
  116.             TempP: IntPtr;                    {*A temporary pointer for getting the address of the resource in memory.*}
  117.  
  118.     begin
  119.         Err := noErr;                {*Initially return an error code of zero*}
  120.         BuildMenu := nil;            {*Initially return a nil handle in case of error.*}
  121.         TempMasterHandle := MHandle(NewHandle(SizeOf(MItemList)));            {*Create a temporary handle to hold this item.*}
  122.         if TempMasterHandle = nil then            {*Check to make sure the handle was allocated properly.*}
  123.             begin
  124.                 Err := NilHandle;                    {*If not, return from function with proper error code.*}
  125.                 Exit(BuildMenu);
  126.             end;
  127.         TheMasterHandle := TempMasterHandle;        {*Hold the handle to the first item in the item list.*}
  128.         RHandle := GetResource('HmiL', HmiLID);        {*Read in the 'HmiL' resource.*}
  129.         if RHandle = nil then                        {*Check to see if the resource was read into memory.*}
  130.             begin
  131.                 Err := HmiLNotAvail;                    {*If not, return from function with proper error code.*}
  132.                 Exit(BuildMenu);
  133.             end;
  134.  
  135.         HLock(RHandle);                {*Lock the handle down since we will be dereferencing it into an address shortly.*}
  136.         TempP := intPtr(stripAddress(RHandle^));            {*Create a pointer to the first integer in the 'HmiL' resource*}
  137.         Count := TempP^;                        {*Take the first integer in the resource and save for use in looping.*}
  138.         Address := Ord4(stripAddress(RHandle^));        {*Get the  stripped address of the resource in memory.*}
  139.         repeat
  140.             Address := Address + 2;                        {*Move the address up two bytes to miss the integer we are pointing at now.*}
  141.             TempPtr := StringPtr(Pointer(Address));        {*Get a temporary pointer to the current address.*}
  142.             TheItemTitle := TempPtr^;                        {*Get the item's title directly from the address location.*}
  143.             Address := Address + Length(TheItemTitle) + 1;    {*Calculate the new address*}
  144.  
  145.             if (length(TheItemTitle) mod 2 = 0) then
  146.                 Address := Address + 1;
  147.                                 {*If the Title length is odd, account for the padding.*}
  148.  
  149.             TempItemRec := IListPtr(Pointer(Address));
  150.                 {*Force the rest of the first item into a record for easier usage.*}
  151.             if TempItemRec^.HierMenu then        {*If this item is a hierarchical menu then build that menu*}
  152.                 begin
  153.                     TheItemTitle := Concat(TheItemTitle, '/', chr($1B), '!', chr(TempItemRec^.HierMenuID));
  154.                 {*Set up the item title for use as a hierarchical menu.*}
  155.                     AppendMenu(TheMenuHandle, TheItemTitle);        {*Stick it in the menu.*}
  156.                     HierMHandle := NewMenu(TempItemRec^.HierMenuID, 'Hier Help Menu');
  157.                 {*Create a new menu for the hierarchical item.*}
  158.                     TheMenu[whichMenu].ID := TempItemRec^.HierMenuID;      {*Add this menu ID to the array of menus.*}
  159.                     InsertMenu(HierMHandle, -1);            {*Insert the new menu.*}
  160.                     whichMenu := whichMenu + 1;            {*We are on the next menu now.*}
  161.                     TheMenu[whichMenu].Master := BuildMenu(TempItemRec^.HierMItemListID, HierMHandle, whichMenu, Err);
  162.                 {*Recursively call this function to build each menu as we come to it.*}
  163.                     if Err <> noErr then
  164.                         Exit(BuildMenu);            {*If we had an error, drop out of the BuildMenu routine with the appropriate error code.*}
  165.                     whichMenu := whichMenu - 1;            {*We are on the previous menu again.*}
  166.                 end
  167.             else
  168.                 begin
  169.                     AppendMenu(TheMenuHandle, TheItemTitle);        {*If not hierarchical menu, add this item to the menu.*}
  170.                     TheMenu[whichMenu].ID := TheMenuHandle^^.menuID;            {*Set the menu ID in the array*}
  171.                 end;
  172.             TempMasterHandle^^.ItemTitle := TheItemTitle;        {*Store the item's title in our menu list.*}
  173.             TempMasterHandle^^.HelpTextID := TempItemRec^.HelpTextID;    {*Store the ID of the help text resource in our menu list.*}
  174.  
  175.             if (Count - 1) = 0 then                    {*Check to see if we are on last item.*}
  176.                 TempMasterHandle^^.NextItem := nil        {*If so, there is no next item so make it nil.*}
  177.             else
  178.  
  179.                 begin            {*If we are not on the last item, allocate space for the next item.*}
  180.                     TempMHandle := MHandle(NewHandle(SizeOf(MItemList)));        {*Get a handle to our next item.*}
  181.                     if TempMHandle = nil then            {*Check to make sure the handle was allocated properly.*}
  182.                         begin
  183.                             Err := NilHandle;                    {*If not, return from function with proper error code.*}
  184.                             Exit(BuildMenu);
  185.                         end;
  186.                     TempMasterHandle^^.NextItem := TempMHandle;            {*Store the handle to our next item in our menu list.*}
  187.                     TempMasterHandle := TempMHandle;                    {*Set the master handle to the next Item.*}
  188.                 end;
  189.  
  190.             Address := Ord4(@TempItemRec^.HelpTextID);        {*Move our address up to the last item in this record.*}
  191.             Count := Count - 1;        {*We processed one item so remove from the count of items.*}
  192.  
  193.         until Count = 0;        {*We are done when count reaches zero*}
  194.         HUnlock(RHandle);                    {*Unlock the handle we were just working with*}
  195.         ReleaseResource(RHandle);            {*Release the resource since we don't need it anymore*}
  196.         BuildMenu := TheMasterHandle;            {*Return the master handle to the calling routine.*}
  197.     end;
  198. {-----------------------------------------------------------------------}
  199.  
  200.  
  201.     function InitHelp (HmiLID: integer): Integer;
  202.  
  203.         var
  204.             Error: OSErr;                {*Used to report any operating system errors.*}
  205.             response: Longint;            {*Used for responses from the Gestalt function*}
  206.             Err: Integer;                {*Used to report any errors from within my Build Menu function*}
  207.             menuNum: integer;            {*Basically a dummy variable on this level*}
  208.  
  209.     begin
  210.         InitHelp := noErr;                                    {*Start with no error.*}
  211.         HelpMenuHandle := nil;            {*Make sure the handle is nil initially for error trapping*}
  212.         if not USEHMENUS then
  213.             if TrapAvailable(_Gestalt) then        {*Check to see if the Gestalt function is available.*}
  214.                 begin
  215.                     if Gestalt(gestaltHelpMgrAttr, response) = noErr then    {*Check for an error in calling the Gestalt function.*}
  216.                         if (BTST(response, gestaltHelpMgrPresent)) then        {*Test the response to see if the Help Manager is present.*}
  217.                             if HMGetHelpMenuHandle(HelpMenuHandle) = noErr then    {*Check for an error in getting the handle.*}
  218.                                 HelpMenuID := kHMHelpMenuID;                {*If the Help manager is present and we had no*}
  219.                         {*problem getting a handle to the Help menu then we are using System 7 stuff*}
  220.  
  221.                 end;        {*Otherwise we need to try to build a new menu and add it to the menu bar*}
  222.         if HelpMenuHandle = nil then    {*We didn't get a handle to the Help menu, so try to create a new menu*}
  223.             begin
  224.                 HelpMenuHandle := NewMenu(NonSevenMenuID, HELPMENUTITLE);    {*Get the new menu*}
  225.                 if HelpMenuHandle = nil then
  226.                     begin
  227.                         InitHelp := HelpHandleErr;            {*If there was a problem getting a handle to the menu*}
  228.                         exit(InitHelp);            {*Exit this routine with proper error code.*}
  229.                     end;
  230.                 insertMenu(HelpMenuHandle, 0);    {*Put the new menu in the menubar*}
  231.                 HelpMenuID := NonSevenMenuID;    {*Set the menu ID for non-System 7 Help menu*}
  232.             end;
  233.         HelpMenuItems := CountMItems(HelpMenuHandle);        {*Get the number of menu items initally*}
  234.  
  235.         menuNum := 0;                {*The number of the menu we are currently working with.*}
  236.         TheMenu[menuNum].Master := BuildMenu(HmiLID, HelpMenuHandle, menuNum, Err);
  237.             {*Build the first Menu, recursively build the rest and store the master handle.*}
  238.  
  239.         if Err <> noErr then            {*Check for an error during the build sequence.*}
  240.             InitHelp := Err;                {*Return proper error code.*}
  241.  
  242.         DrawMenuBar;                {*Update the menu bar to include all of the new items added.*}
  243.     end;
  244. {-----------------------------------------------------------------------}
  245.  
  246.     procedure MoveText;
  247.  
  248.         var
  249.             OldOffset, NewOffset: integer;        {*The old and new offset of the text in pixels*}
  250.  
  251.     begin
  252.         with TEXTHandle^^ do
  253.             begin
  254.                 OldOffset := viewRect.top - destRect.top;    {*Calculate the old offset*}
  255.                 NewOffset := GetCtlValue(TheScrollBar) * lineheight;        {*Calculate the offset to the new posn.*}
  256.                 TEScroll(0, (OldOffset - NewOffset), TEXTHandle);        {*Scroll to the new position*}
  257.             end;
  258.     end;
  259. {-----------------------------------------------------------------------}
  260.  
  261.     procedure ScrollPageUp;
  262.  
  263.         var
  264.             OldControl: integer;
  265.             change: integer;
  266.  
  267.     begin
  268.         OldControl := GetCtlValue(TheScrollBar);                {*Get the old value*}
  269.         with TEXTHandle^^.viewrect do
  270.             change := (top - bottom) div TEXTHandle^^.lineheight;
  271.         SetCtlValue(TheScrollBar, OldControl + change);        {*Set the new value*}
  272.         MoveText;
  273.     end;
  274. {-----------------------------------------------------------------------}
  275.  
  276.     procedure ScrollPageDown;
  277.  
  278.         var
  279.             OldControl: integer;
  280.             change: integer;
  281.  
  282.     begin
  283.         OldControl := GetCtlValue(TheScrollBar);                {*Get the old value*}
  284.         with TEXTHandle^^.viewrect do
  285.             change := (bottom - top) div TEXTHandle^^.lineheight;
  286.         SetCtlValue(TheScrollBar, OldControl + change);        {*Set the new value*}
  287.         MoveText;
  288.     end;
  289. {-----------------------------------------------------------------------}
  290.  
  291.     procedure ScrollUp;
  292.  
  293.         var
  294.             OldControl: integer;
  295.  
  296.     begin
  297.         OldControl := GetCtlValue(TheScrollBar);                {*Get the old value*}
  298.         SetCtlValue(TheScrollBar, OldControl - 1);        {*Set the new value*}
  299.         MoveText;
  300.     end;
  301. {-----------------------------------------------------------------------}
  302.  
  303.     procedure ScrollDown;
  304.  
  305.         var
  306.             OldControl: integer;
  307.  
  308.     begin
  309.         OldControl := GetCtlValue(TheScrollBar);                {*Get the old value*}
  310.         SetCtlValue(TheScrollBar, OldControl + 1);        {*Set the new value*}
  311.         MoveText;
  312.     end;
  313. {-----------------------------------------------------------------------}
  314.  
  315.     procedure ScrollTop;
  316.  
  317.         var
  318.             TopValue: integer;
  319.  
  320.     begin
  321.         TopValue := GetCtlMin(TheScrollBar);                        {*Get the minimum value*}
  322.         SetCtlValue(TheScrollBar, TopValue);                        {*Set the control to top*}
  323.         MoveText;
  324.     end;
  325. {-----------------------------------------------------------------------}
  326.  
  327.     procedure ScrollBottom;
  328.         var
  329.             BottomValue: integer;
  330.  
  331.     begin
  332.         BottomValue := GetCtlMax(TheScrollBar);                    {*Get the maximum value*}
  333.         SetCtlValue(TheScrollBar, BottomValue);                    {*Set the control to bottom*}
  334.         MoveText;
  335.     end;
  336. {-----------------------------------------------------------------------}
  337.  
  338.     procedure ContinuousScroll (theControl: controlHandle; thePart: integer);
  339.  
  340.         var
  341.             change: integer;            {*The amount of scrolling change*}
  342.             OldControl: integer;        {*The old value of the control*}
  343.  
  344.     begin
  345.         case thePart of
  346.             inUpButton: 
  347.                 change := -1;                {*If mouse in upButton, scroll text up 1 line*}
  348.             inDownButton: 
  349.                 change := 1;                {*If mouse in downButton, scroll text down 1 line*}
  350.             inPageup: 
  351.                 with TEXTHandle^^.viewrect do
  352.                     change := (top - bottom) div TEXTHandle^^.lineheight;
  353.     {*If mouse in page up, move text up 1 page*}
  354.             inPagedown: 
  355.                 with TEXTHandle^^.viewrect do
  356.                     change := (bottom - top) div TEXTHandle^^.lineheight;
  357.         {*If mouse in page down, move text down 1 page*}
  358.         end;
  359.         if thePart <> 0 then                                        {*Are we still in the same part?*}
  360.             begin
  361.                 OldControl := GetCtlValue(theControl);                {*Get the old value*}
  362.                 SetCtlValue(theControl, OldControl + change);        {*Set the new value*}
  363.                 MoveText;
  364.             end;
  365.     end;
  366. {-----------------------------------------------------------------------}
  367.  
  368.     function HelpFilter (theDialog: DialogPtr; var theEvent: EventRecord; var ItemNum: INTEGER): Boolean;
  369.  
  370.         const
  371.             enterKey = 3;
  372.             CR = 13;
  373.             Home = $73;
  374.             Bottom = $77;            {*Char and key codes for keyboard events*}
  375.             PageU = $74;
  376.             PageD = $79;
  377.             ArrowUp = 30;
  378.             ArrowDown = 31;
  379.  
  380.         var
  381.             dummyint: integer;
  382.             dummyh: handle;            {*Dummy variables for GetDItem calls*}
  383.             TextRect: rect;                {*The rect of the Text area*}
  384.             thePoint: Point;                    {*The point of a mousedown event*}
  385.             thePart: Integer;                {*The part of the control where the mouse was pressed*}
  386.             theControl: ControlHandle;    {*The control the mouse was pressed in*}
  387.             thePen: PenState;            {*Holds the old pen state*}
  388.             tempLong: longint;                {*Temporary long integer*}
  389.             theKey: Longint;                {*The key code for a key event*}
  390.             TextRgn, TempRgn: RgnHandle;    {*Used in determining if the text needs updating*}
  391.             theDialogPeek: DialogPeek;        {*Used to get the update region of the dialog*}
  392.  
  393.     begin
  394.         HelpFilter := False;
  395.         case theEvent.what of
  396.             UpdateEvt: 
  397.                 if theEvent.message = ord4(theDialog) then
  398.                     begin
  399.                         GetDItem(theDialog, TextBox, dummyint, dummyh, TextRect); {*Get location*}
  400.                         insetrect(TextRect, 1, 1);
  401.                         GetPenState(thePen);                               {*Save current pen*}
  402.                         Pensize(2, 2);
  403.                         insetrect(TextRect, -2, -2);        {*Set rectangle to 2 pixels outside of text area*}
  404.                         FrameRect(TextRect);                                {*Draw rect around text*}
  405.                         InsetRect(TEXTRect, 2, 2);            {*Set rectangle to text area*}
  406.                         EraseRect(TextRect);                {*Erase the text*}
  407.                         TEUpdate(TextRect, TEXTHandle);        {*Redraw the text*}
  408.  
  409.                         GetDItem(theDialog, 1, dummyint, dummyh, TextRect);        {*Get the rect of the ok button*}
  410.                         Pensize(3, 3);                                            {*Set the pen to 3 pixels by 3 pixels*}
  411.                         InsetRect(TextRect, -4, -4);                                {*Set the rect around the button*}
  412.                         FrameRoundRect(TextRect, 16, 16);                        {*Draw the outline*}
  413.                         SetPenState(thePen);                                    {*Restore the old pen*}
  414.                     end;
  415.  
  416.             keydown, autokey: 
  417.                 begin
  418.                     HelpFilter := true;            {*Assume we will take care of event*}
  419.                     Itemnum := 3;                {*Assume a hit on the scroll bar*}
  420.                     theKey := BitAnd(theEvent.message, charCodeMask);  {*Decode character code*}
  421.                     case theKey of
  422.                         enterKey, CR: 
  423.                             begin
  424.                                 GetDItem(theDialog, 1, dummyint, dummyh, TextRect);
  425.                                 HiliteControl(ControlHandle(dummyh), 1);            {*Fake a click on the OK button*}
  426.                                 Delay(8, tempLong);
  427.                                 HiliteControl(ControlHandle(dummyh), 0);
  428.                                 ItemNum := 1;        {*Let ModalDialog know OK button was hit*}
  429.                             end;
  430.                         ArrowUp: 
  431.                             Scrollup;            {*Scroll text up one line*}
  432.                         ArrowDown: 
  433.                             ScrollDown;            {*Scroll text down one line*}
  434.                         otherwise
  435.                             begin
  436.                                 theKey := (BitAnd(theEvent.message, KeyCodeMask)) div 256;  {*Decode key code*}
  437.                                 case theKey of
  438.                                     Home: 
  439.                                         ScrollTop;            {*Set text to top*}
  440.                                     Bottom: 
  441.                                         ScrollBottom;        {*Set text to bottom*}
  442.                                     PageU: 
  443.                                         ScrollPageup;        {*Scroll text up one page*}
  444.                                     PageD: 
  445.                                         ScrollPageDown;    {*Scroll text down one page*}
  446.                                     otherwise
  447.                                         HelpFilter := false;        {*Set return to false if none of these conditions matched*}
  448.                                 end;    {*Case*}
  449.                             end;        {*Otherwise*}
  450.                     end;
  451.                 end;
  452.  
  453.             MouseDown: 
  454.                 begin
  455.                     thePoint := theEvent.where;        {*Get the point where the mouse was pressed*}
  456.                     GlobaltoLocal(thePoint);            {*Convert the point to local coordinates*}
  457.  
  458.                     thePart := FindControl(thePoint, theDialog, theControl);    {*Was mouse in a control?*}
  459.                     if thecontrol = TheScrollBar then
  460.                         if thePart = InThumb then
  461.                             begin
  462.                                 thePart := TrackControl(TheScrollBar, thePoint, nil);
  463.                                 MoveText;        {*Adjust the text to the movement*}
  464.                                 HelpFilter := true;    {*We handled the event don't let modal dialog take further action*}
  465.                                 ItemNum := 3    {*Give the return value a number that doesn't correspond to the ok button*}
  466.                             end
  467.                         else
  468.                             begin
  469.                                 thePart := TrackControl(TheScrollBar, thePoint, @ContinuousScroll);
  470.                                 HelpFilter := true;    {*We handled the event don't let modal dialog take further action*}
  471.                                 ItemNum := 3    {*Give the return value a number that doesn't correspond to the ok button*}
  472.                             end
  473.                 end;
  474.         end;
  475.     end;
  476. {-----------------------------------------------------------------------}
  477.  
  478.     function DoHelp (MenuID, TheItem: integer): Integer;
  479.  
  480.         const
  481.             HelpDialogID = 20000;        {*The ID of the Help dialog resource*}
  482.             TheControl = 3;                {*The item number of the scroll bar in the help dialog*}
  483.  
  484.         var
  485.             tempHandle: MHandle;        {*A temporary handle used in traversing the linked list of menu items.*}
  486.             TextID: integer;            {*Will hold the ID of the 'TEXT' resource for the selected item.*}
  487.             TheTitle: Str255;            {*The title of the menu item selected*}
  488.             HelpDialogPtr: DialogPtr;    {*The pointer to the Help Dialog box*}
  489.             DummyKind: Integer;        {*A dummy for use in Get and SetDItem.*}
  490.             TheRect: Rect;                {*A rectangle for use in GetDItem.*}
  491.             DummyHandle: Handle;        {*A dummy for use in GetDItem.*}
  492.             TheText: Handle;            {*A handle to the TEXT resource*}
  493.             DestRect: rect;                {*The destination rectangle of the text*}
  494.             MaxLines, LinesVisible: integer;        {*Values needed for calculating scrollbar values*}
  495.             TextLength: longint;        {*Holds the length of the TEXT resource*}
  496.             SavePort: GrafPtr;        {*Holds the old port*}
  497.             TheMenuHandle: MenuHandle;        {*Holds the menuHandle of the menu ID passed in*}
  498.  
  499.     begin
  500.         TextID := 0;                    {*Initially, no TEXT resource selected*}
  501.         DummyKind := 0;                {*Start with element 0*}
  502.         while (TheMenu[DummyKind].ID <> MenuID) and (DummyKind <= MaxMenu) do
  503.             DummyKind := DummyKind + 1;        {*Find the LL of the requested menu*}
  504.  
  505.         if DummyKind > MaxMenu then        {*If DummyKind exceeds the number of allowed menus,*}
  506.             begin                                {*the menu is not associated with the Help menu*}
  507.                 DoHelp := NoMenu;                {*so return with proper code*}
  508.                 exit(DoHelp)
  509.             end;
  510.  
  511.         TheMenuHandle := GetMHandle(MenuID);            {*Get a handle to the selected menu*}
  512.         GetItem(TheMenuHandle, TheItem, TheTitle);        {*Get the title of the selected item*}
  513.         tempHandle := TheMenu[DummyKind].Master;            {*Set tempHandle equal to the master pointer of the LL.*}
  514.         while TheTitle <> TempHandle^^.ItemTitle do            {*Search for the selected item*}
  515.             begin
  516.                 tempHandle := TempHandle^^.NextItem;
  517.                 if tempHandle = nil then        {*This occurs only if we are past the last item in the list.*}
  518.                     begin
  519.                         DoHelp := DataErr;            {*This signifies a data corruption error.*}
  520.                         exit(DoHelp)
  521.                     end;
  522.             end;
  523.         TextID := TempHandle^^.HelpTextID;            {*Set the TEXT ID to the one from the menu item list*}
  524.  
  525.         HelpDialogPtr := GetNewDialog(HelpDialogID, nil, windowPtr(-1));        {*Get the Help Dialog*}
  526.         getport(SavePort);            {*Save the old port*}
  527.         SetPort(HelpDialogPtr);        {*Set the port to the new dialog*}
  528.         GetDItem(HelpDialogPtr, TheControl, DummyKind, DummyHandle, TheRect);
  529.         TheScrollBar := ControlHandle(DummyHandle);    {*Get a control handle to the scroll bar*}
  530.  
  531.         TheText := GetResource('TEXT', TextID);            {*Get the TEXT resource*}
  532.         if TheText = nil then
  533.             begin
  534.                 DoHelp := DataErr;
  535.                 exit(DoHelp)        {*This signifies a data corruption error or TEXT resource not available.*}
  536.             end;
  537.  
  538.         GetDItem(HelpDialogPtr, TextBox, DummyKind, DummyHandle, TheRect);
  539.             {*Get the rect of the text box*}
  540.  
  541.         with DestRect do
  542.             begin
  543.                 top := TheRect.top + 1;
  544.                 left := TheRect.left + 1;
  545.                 right := TheRect.right - 1;
  546.                 bottom := 20000;        {*Set the bottom way down*}
  547.             end;
  548.         InsetRect(TheRect, 1, 1);
  549.         TEXTHandle := TENew(DestRect, TheRect);        {*Create a new TE record*}
  550.         Hlock(Handle(TEXTHandle));            {*Lock the text handle down so we can dereference it.*}
  551.  
  552. {** THESE ARE SET WITH THE GLOBAL VARIABLES **}
  553.         TEXTHandle^^.txFont := FONTFACE;        {*Set Font to Selected font face*}
  554.         TEXTHandle^^.txSize := FONTSIZE;    {*Set size to selected font size*}
  555.  
  556.         TextLength := SizeResource(TheText);        {*Get the length of the text*}
  557.         TEDEactivate(TEXTHandle);
  558.         HLock(TheText);        {*Lock down the handle*}
  559.         TEInsert(TheText^, TextLength, TEXTHandle);
  560.         HUnlock(TheText);
  561.  
  562.         with TEXTHandle^^ do
  563.             LinesVisible := (ViewRect.bottom - ViewRect.Top) div lineHeight;
  564.  
  565.         if TEXTHandle^^.nLines > LinesVisible then
  566.             begin
  567.                 HiliteControl(TheScrollBar, 0);        {*Enable scrollbar if lines are out of view*}
  568.                 MaxLines := TEXTHandle^^.nLines - LinesVisible - 1;
  569.                 SetCtlMax(TheScrollBar, MaxLines);        {*Set the maximum value of the control*}
  570.             end
  571.         else
  572.             begin
  573.                 HiliteControl(TheScrollBar, 255);        {*Disable the scrollbar if all lines are visible*}
  574.             end;
  575.  
  576.         ShowWindow(HelpDialogPtr);        {*Show the window*}
  577.         invalrect(HelpDialogptr^.portrect);            {*Force an update on the dialog*}
  578.         repeat
  579.             ModalDialog(@HelpFilter, DummyKind);    {*Using dummyKind to save some space*}
  580.         until DummyKind = ok;
  581.  
  582.         HUnlock(Handle(TEXTHandle));        {*Unlock the text handle*}
  583.         DisposDialog(HelpDialogPtr);
  584.         ReleaseResource(TheText);            {*Get rid of all this junk before returning*}
  585.         TEDispose(TEXTHandle);
  586.         DoHelp := noErr;                        {*Return with no error*}
  587.         Setport(SavePort);                    {*Return port to previous one*}
  588.     end;
  589. {-----------------------------------------------------------------------}
  590.  
  591.     procedure DisposeHelp;
  592.  
  593.         var
  594.             TempHandle: MHandle;
  595.             DisposableH: MHandle;
  596.             loop: integer;
  597.             MenuItems: integer;            {*The number of items in the Help Menu now.*}
  598.  
  599.     begin
  600.         MenuItems := CountMItems(HelpMenuHandle);        {*Count the number of items in the Help Menu now*}
  601.  
  602.         for loop := HelpMenuItems + 1 to MenuItems do
  603.             begin
  604.                 DelMenuItem(HelpMenuHandle, HelpMenuItems + 1);        {*Delete all items in the menu*}
  605.             end;
  606.  
  607.         if HelpMenuHandle^^.menuData = HELPMENUTITLE then
  608.             begin                            {*If not system 7 help menu we need to kill it.*}
  609.                 deleteMenu(HelpMenuID);            {*Remove the menu from the menu bar*}
  610.                 DrawMenuBar;                        {*Update menu bar in case application has just turned*}
  611.                         {*off this help system*}
  612.                 DisposeMenu(HelpMenuHandle);        {*Release the menu from memory*}
  613.             end;
  614.  
  615.         for loop := 0 to MaxMenu do        {*Dispose of all lists*}
  616.             begin
  617.                 DisposableH := TheMenu[loop].Master;            {*Get the handle to the first linked list*}
  618.                 while DisposableH <> nil do
  619.                     begin
  620.                         TempHandle := DisposableH^^.NextItem;        {*Store the handle to the next item*}
  621.                         DisposHandle(Handle(DisposableH));                    {*Dispose of the original handle*}
  622.                         DisposableH := TempHandle;                {*Setup for next disposal*}
  623.                     end;                                        {*Keep going until all handles in this list are gone*}
  624.             end;
  625.     end;
  626. end.